// The hypergol command converts hypergol files (a mixture of Go and HTML) to
// plain Go files. The files must import the hypergol package. The processed
// text is output to files that have the same name as the input, but with an
// additional ".go" extension.
//
// The hypergol format allows embedding HTML in Go source files, like this:
//
//		div := <div class="my-div">"Hello, world"</div>
//
// This is roughly equivalent to:
//
//		div := &html.Node{
//			Type: html.ElementNode,
//			Data: "div",
//			Attr: []html.Attribute{
//				{
//					Key: "class",
//					Val: "my-div",
//				},
//			},
//		}
//		div.AppendChild(&html.Node{
//			Type: html.TextNode,
//			Data: "Hello, world",
//		})
//
// Note that the HTML syntax is nonstandard. Attribute values and text content
// are Go expressions. This allows arbitrary values to be substituted into the
// HTML (like <p>"1 + 1 is " 1 + 1</p>, which results in <p>1 + 1 is 2</p>),
// but requires that literal text be in quotes, like "Hello, world" in the
// example above.
//
// Another peculiarity is that Go expressions used in HTML must not include the
// < or > operators, except inside parentheses. If a line ends with an HTML 
// tag, the lexer will not insert a semicolon there, since statements can't end 
// with > in plain Go; you will need to put a semicolon in manually.
package main

import (
	"bytes"
	"fmt"
	"go/printer"
	"go/token"
	"io/ioutil"
	"log"
	"os"

	"code.google.com/p/hypergol/parser"
)

func main() {
	args := os.Args[1:] // Drop the program name.
	if len(args) == 0 {
		fmt.Fprintln(os.Stderr, "Usage:")
		fmt.Fprintln(os.Stderr, "    hypergol file ...")
		os.Exit(1)
	}

	fs := token.NewFileSet()

	for _, file := range args {
		err := processFile(fs, file)
		if err != nil {
			log.Fatalf("Error processing file %q: %v", file, err)
		}
	}
}

func processFile(fs *token.FileSet, file string) error {
	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()
	content, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}

	tree, err := parser.ParseFile(fs, file, content, parser.ParseComments)
	if err != nil {
		return err
	}

	var buf bytes.Buffer
	err = (&printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}).Fprint(&buf, fs, tree)
	if err != nil {
		return err
	}
	res := buf.Bytes()

	out, err := os.Create(file + ".go")
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = out.Write(res)
	return err
}
